DearMiku

RXSwift源码浅析(二)

字数统计: 2.1k阅读时长: 9 min
2017/12/19 Share

RXSwift 源码浅析(二)

简述

本文是对上一篇文章的补充,加上对KVO实现的简要分析 和 自己的一些思考,可能会有不够准确的地方还望多多指正,共同学习~~

框架结构

在上篇文章中是从具体实现的角度分析Observable的使用实现,接下来从一个高一点的角度来分析RXSwift.

效果

无论是Observable,还是KVO,通知,按钮点击….,在本质上我认为可将这一切看为这样一个过程~

screenshot
以通知为例子, 在程序中某个地方发出了事件(例如键盘弹出),这就是事件源. 然后这个事件传递(系统发出键盘弹出的通知). 最后程序的某处响应了这个事件(比如我们监听到这个通知,然后将控件上移). 我认为RXSwift就是为了让大家更方便的实现这样的过程~

而RXSwift的结构就大概是这样的

结构简图

1,事件源
screenshot
例如create函数~

2,响应
screenshot
为了简洁,我并没有加入资源释放那部分, 具体的可以参照上篇进行对比的来看, 中介在事件源中接受事件,在响应中输出事件.

接下啦我再以KVO的实现细节 再来展示一下这个结构~~

KVO实现细节

下面是一段日常使用RXSwift的代码~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Test: NSObject {
@objc var name:String!
}

class ViewController: UIViewController {
@objc var obj:Test!
var disposeBag = DisposeBag()

override func viewDidLoad() {
super.viewDidLoad()
obj = Test()
obj.rx.observe(String.self, #keyPath(Test.name)).subscribe { (eve) in
print(eve)
}.disposed(by: self.disposeBag)
}
}

事件源

rx

首先第一步是调用对象的rx属性, rx来源于 对NSObject的扩展协议~

1
2
import class Foundation.NSObject
extension NSObject: ReactiveCompatible { }

协议实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

public protocol ReactiveCompatible {

associatedtype CompatibleType

// 类属性 和 对象属性~
static var rx: Reactive<CompatibleType>.Type { get set }
var rx: Reactive<CompatibleType> { get set }
}

extension ReactiveCompatible {
public static var rx: Reactive<Self>.Type {
get {
return Reactive<Self>.self
}
set {
}
}
public var rx: Reactive<Self> {
get {
return Reactive(self)
}
set {
}
}
}

这里其实是为了将当前对象封装为一个Reactive结构体

1
2
3
4
5
6
7
public struct Reactive<Base> {          
public let base: Base

public init(_ base: Base) {
self.base = base
}
}

observe

一般我们调用的是这个扩展方法

1
2
3
4
5
6
7
extension Reactive where Base: NSObject {

public func observe<E>(_ type: E.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial], retainSelf: Bool = true) -> Observable<E?> {

return KVOObservable(object: base, keyPath: keyPath, options: options, retainTarget: retainSelf).asObservable()
}
}

observe方法首先创建一个KVOObservable对象~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//YSD--产生KVO的可观察者
fileprivate final class KVOObservable<Element>: ObservableType
, KVOObservableProtocol {

typealias E = Element?

unowned var target: AnyObject
var strongTarget: AnyObject?

var keyPath: String
var options: KeyValueObservingOptions
var retainTarget: Bool

//初始化方法
init(object: AnyObject, keyPath: String, options: KeyValueObservingOptions, retainTarget: Bool) {
self.target = object
self.keyPath = keyPath
self.options = options
self.retainTarget = retainTarget
if retainTarget {
self.strongTarget = object
}
}

//订阅方法~~~
func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == Element? {
let observer = KVOObserver(parent: self) { (value) in
if value as? NSNull != nil {
observer.on(.next(nil))
return
}
observer.on(.next(value as? Element))
}
return Disposables.create(with: observer.dispose)
}
}

..............

fileprivate protocol KVOObservableProtocol {
var target: AnyObject { get }
var keyPath: String { get }
var retainTarget: Bool { get }
var options: KeyValueObservingOptions { get }
}

KVOObservable对象遵守ObservableType协议,所以可以调用asObsevable()方法, KVOObservableProtocol协议限定它持有这些KVO 必须的属性~,因为在本质上,还是调用OC的KVO实现~

动态语言还是爽呀~

订阅方法

订阅时也就是上面重载的方法~ 首先还是创建一个观察者,来持有 事件响应的闭包~

1
2
3
4
5
6
7
let observer = KVOObserver(parent: self) { (value) in
if value as? NSNull != nil {
observer.on(.next(nil))
return
}
observer.on(.next(value as? Element))
}

然而事件是从哪里发出的呢~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
fileprivate final class KVOObserver
: _RXKVOObserver
, Disposable {


typealias Callback = (Any?) -> Void

var retainSelf: KVOObserver? = nil

init(parent: KVOObservableProtocol, callback: @escaping Callback) {
#if TRACE_RESOURCES
_ = Resources.incrementTotal()
#endif

super.init(target: parent.target, retainTarget: parent.retainTarget, keyPath: parent.keyPath, options: parent.options.nsOptions, callback: callback)

//因为 可观察者并不强引用它,所以通过循环引用 保持自己不被回收
self.retainSelf = self
}

//只用调用dispose后才会回收,所以大家注意 不要因为偷懒不好好使用disposeBag(๑•ᴗ•๑)
override func dispose() {
super.dispose()
self.retainSelf = nil
}

deinit {
#if TRACE_RESOURCES
_ = Resources.decrementTotal()
#endif
}
}

相对应它的父类就是OC实现的~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@interface _RXKVOObserver ()
//和weak差不多, 但是weak释放了为变为nil 它不会 会因为野指针的使用而崩溃
@property (nonatomic, unsafe_unretained) id target;
@property (nonatomic, strong ) id retainedTarget;
@property (nonatomic, copy ) NSString *keyPath;
@property (nonatomic, copy ) void (^callback)(id);

@end

@implementation _RXKVOObserver

-(instancetype)initWithTarget:(id)target
retainTarget:(BOOL)retainTarget
keyPath:(NSString*)keyPath
options:(NSKeyValueObservingOptions)options
callback:(void (^)(id))callback {
self = [super init];
if (!self) return nil;

self.target = target;
if (retainTarget) {
self.retainedTarget = target;
}
self.keyPath = keyPath;
self.callback = callback;

[self.target addObserver:self forKeyPath:self.keyPath options:options context:nil];

return self;
}

//常规的操作,将监听到的新值作为block参数返回
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
@synchronized(self) {
self.callback(change[NSKeyValueChangeNewKey]);
}
}

-(void)dispose {
[self.target removeObserver:self forKeyPath:self.keyPath context:nil];
self.target = nil;
self.retainedTarget = nil;
}

将KVO的newValue作为参数传入 callBack闭包中~

所以RXSwift对于 KVO的实现就比较简单了,观察者既是事件源 也是 中介 总的来说是将 普通的KVO写法 进行封装,纳入自己的体系之下

反思~

学而不思则罔,思而不学则殆. 所以看完大神的源码一定要反思~ 不然除了框架用的更熟练 跟没看一样~

面向协议

我认为RXSwift就是一个我们学习面向协议编程(Protocol-oriented programming)的好例子~, 通过协议 我们可以很好的解决继承带来的种种弊端~

1, 可以实现在OC和Swift不允许的 多继承~
2, 避免基类受制于子类, 实现依赖倒转, 让子类受制于协议~

在RXSwift中有一些重要的协议ObservableType,ObserverType,Disposable

ObservableType

1
2
3
4
public protocol ObservableType : ObservableConvertibleType {

func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
}

ObserverType

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public protocol ObserverType {
associatedtype E

func on(_ event: Event<E>)
}

extension ObserverType {

public func onNext(_ element: E) {
on(.next(element))
}

public func onCompleted() {
on(.completed)
}

public func onError(_ error: Swift.Error) {
on(.error(error))
}
}

Disposable

1
2
3
public protocol Disposable {
public func dispose()
}

通过这些协议 将各个角色类的行为加以限制, 而各个协议之间是互相对接的,这样即使各个类不相同,只要大家遵守相同的协议,就可以在这个体系下畅通无阻~ . 打个简单的例子就是 弹幕功能

从服务器发来的需要展示的消息是各种各样的(普通弹幕,礼物弹幕,贵族弹幕,管理信息弹幕~~~~),当其实在显示的时候,只需要显示文字和图片而已~ 这样让 消息都遵守可以获取文字图片的协议,这样不管发过来什么消息 都可以正常显示~
当然使用继承也可以实现,但是若我们要加新的消息类型(礼物火箭),这时继承要改基类,乱改基类很有可能会影响到其他子类导致Bug,而协议只需要扩展,或者限定类型的扩展~

当然这不是说让大家不要用继承,在RXSwift中也是有继承的~

1
final class AnonymousObserver<ElementType> : ObserverBase<ElementType> {......}

所以我个人是这样认为的,POP这是纲领,不是方案~ 使用的时候要灵活,小范围,少变动的用继承,大范围,多变化的用协议

单一责任原则

在搭架子的时候就将 角色责任 区分好~ 就像最上面的图示一样,,避免类兼数值. 这样无论是对Bug的定位,还是对项目架构的贯彻 都是有好处的~(๑•ᴗ•๑)

最少知道原则

也就是耦合度的问题,我觉得大家都知道写代码要 高内聚,低耦合. 但是怎么做呢~ 在RXSwift中是这样做的,也就是POP 各个角色间通过协议沟通(我到目前为止展示出来的方法,基本上都是协议上的方法),而类通过遵守协议对协议内容进行实现. 这样 耦合的就只有协议,而类只专注对协议的实现

结尾

暂时就反思了这么多~然后有内容再补充吧,下篇就写 flatMap的分析~ 如果老大的需求没下来 应该很快吧~. 文中要有不准确的地方,请多多指正呀(๑•ᴗ•๑)

CATALOG
  1. 1. RXSwift 源码浅析(二)
  2. 2. 简述
  3. 3. 框架结构
    1. 3.1. 效果
    2. 3.2. 结构简图
  4. 4. KVO实现细节
    1. 4.1. 事件源
      1. 4.1.1. rx
      2. 4.1.2. observe
    2. 4.2. 订阅方法
  5. 5. 反思~
    1. 5.1. 面向协议
    2. 5.2. 单一责任原则
    3. 5.3. 最少知道原则
  6. 6. 结尾